#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <regex>
#include "./../include/online/Tools/ProtocolParser.h"

using namespace std;

static int isValidUTF8Character(string *str)
{
    int i, f_size = str->size();
    unsigned char c, c2, c3, c4;
    string to;
    to.reserve(f_size);

    for (i = 0; i < f_size; i++)
    {
        c = (unsigned char)(*str)[i];
        if (c < 32)
        {
            if (c == 9 || c == 10 || c == 13)
            {
                to.append(1, c);
            }
        }
        else if (c < 127)
        {
            to.append(1, c);
        }
        else if (c < 160)
        {
            if (c2 == 128)
            {
                to.append(1, 226);
                to.append(1, 130);
                to.append(1, 172);
            }
            if (c2 == 133)
            {
                to.append(1, 10);
                to.append(1, 13);
            }
        }
        else if (c < 192)
        {
            to.append(1, (unsigned char)194);
            to.append(1, c);
        }
        else if (c < 194)
        {
            to.append(1, (unsigned char)195);
            to.append(1, c - 64);
        }
        else if (c < 224)
        {
            c2 = (unsigned char)(*str)[i + 1];
            if (c2 > 127 && c2 < 192)
            {
                if (c == 194 && c2 < 160)
                {
                    ;
                }
                else
                {
                    to.append(1, c);
                    to.append(1, c2);
                }
                i++;
            }
            else
            {
                to.append(1, (unsigned char)195);
                to.append(1, c - 64);
            }
        }
        else if (c < 240)
        {
            c2 = (unsigned char)(*str)[i + 1];
            c3 = (unsigned char)(*str)[i + 2];
            if (c2 > 127 && c2 < 192 && c3 > 127 && c3 < 192)
            {
                to.append(1, c);
                to.append(1, c2);
                to.append(1, c3);
                i += 2;
            }
            else
            {
                to.append(1, (unsigned char)195);
                to.append(1, c - 64);
            }
        }
        else if (c < 245)
        {
            c2 = (unsigned char)(*str)[i + 1];
            c3 = (unsigned char)(*str)[i + 2];
            c4 = (unsigned char)(*str)[i + 3];
            if (c2 > 127 && c2 < 192 && c3 > 127 && c3 < 192 && c4 > 127 && c4 < 192)
            {
                to.append(1, c);
                to.append(1, c2);
                to.append(1, c3);
                to.append(1, c4);
                i += 3;
            }
            else
            {
                to.append(1, (unsigned char)195);
                to.append(1, c - 64);
            }
        }
        else if (c < 256)
        {
            to.append(1, (unsigned char)195);
            to.append(1, c - 64);
        }
        else
        {
            cout << "WTF? more than 256 values per Byte ? (" << (unsigned int)c << ")" << endl;
        }
    }
    *str = to;
    return 1;
}

int main(int agrc,char *argv[])
{
    int socketfd = socket(AF_INET, SOCK_STREAM, 0);
    if(socketfd == -1)
    {
        perror("socket failed");
        return -1;
    }

    struct sockaddr_in serverAddr;
    memset(&serverAddr, 0, sizeof(serverAddr));

    serverAddr.sin_family = AF_INET;
    serverAddr.sin_port = htons(8888);
    serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1");

    int ret = connect(socketfd, (struct sockaddr *)&serverAddr, sizeof(serverAddr));
    if (ret == -1)
    {
        perror("connect failed");
        return -1; 
    }
    printf("conn has connected!...\n");

    regex reg1("\\[;31m");
    regex reg2("\\[0m");

    char buf[100000] = {0};
    while (1)
    {
        memset(buf, 0, sizeof(buf));

        json j;
        int i;

        cout << endl;
        cout << "1.关键字推荐        2.网页查询       0.退出" << std::endl;
        cout << "请输入要执行的操作：";
        while (1)
        {
            cin >> i;

            if (cin.fail())                 // 输入不是数字，清除错误标志并清空输入缓冲区
            {
                cin.clear();                // 清除错误标志
                cin.ignore(10000, '\n');    // 忽略当前行的输入

                cout<<endl;
                cout<<"输入有误，请重新输入!"<<endl;
                cout << "1.关键字推荐        2.网页查询       0.退出" << endl;
                cout << "请输入要执行的操作：";
                continue;
            }
            
            // 检查输入是否合法
            if (i == 0 || i == 1 || i == 2)
            {
                break;         // 输入合法，退出循环
            }
            else
            {
                cout<<endl;
                cout<<"输入有误，请重新输入!"<<endl;
                cout << "1.关键字推荐        2.网页查询       0.退出" << endl;
                cout << "请输入要执行的操作：";
            }
        }

        if (i == 0)
        {
            cout << "退出中..." << endl;
            sleep(1);
            cout << "已退出！" << endl;
            break;
        }

        std::cin.ignore();      // 清空缓冲区
        string line;            // line存储要查询的内容

        if (i == 1)
        {
            cout << "请输入要查询的关键字:";
            getline(cin, line);
            j["flag"] = "1";
            j["info"] = line;
        }
        else if (i == 2)
        {
            cout << "请输入要查询的网页关键字:";
            getline(cin, line);
            j["flag"] = "2";
            j["info"] = line;
        }

        // 1. 客户端先发数据
        string sendInfo = j.dump();
        sendInfo.push_back('\n');
        int ret = send(socketfd, sendInfo.c_str(), sendInfo.size(), 0);
        cout << sizeof(sendInfo) << endl;

        // 2. 接收查询结果
        ret = recv(socketfd, buf, sizeof(buf), 0);
        j = json::parse(buf);
        vector<string> result;
        ProtocolParser::jsonTovector(j, result);

        for (auto& ele : result)
        {
            isValidUTF8Character(&ele);
            ele = regex_replace(ele, reg1, "\033[;31m");
            ele = regex_replace(ele, reg2, "\033[0m");
            cout << ele << endl;
        }
    }

    close(socketfd);
}

